package com.ptkc.web;

import com.ptkc.constants.Page;
import com.ptkc.constants.WebResult;
import com.ptkc.constants.WebStatus;
import com.ptkc.data.repository.ElasticsearchRepository;
import com.ptkc.utils.DatesUtil;
import com.ptkc.utils.MyUtil;
import com.ptkc.utils.NumberUtils;
import com.ptkc.utils.StringUtil;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.elasticsearch.action.search.*;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.BucketsAggregator;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.terms.*;
import org.elasticsearch.search.aggregations.metrics.cardinality.CardinalityAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.scripted.ScriptedMetricAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.sum.Sum;
import org.elasticsearch.search.aggregations.metrics.sum.SumAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCount;
import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCountAggregationBuilder;
import org.elasticsearch.search.aggregations.pipeline.BucketHelpers;
import org.elasticsearch.search.aggregations.pipeline.bucketscript.BucketScriptPipelineAggregationBuilder;
import org.elasticsearch.search.aggregations.pipeline.bucketscript.BucketScriptPipelineAggregator;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.ScriptSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.data.domain.Pageable;

import javax.management.Query;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;

/**
 * @author: Mr.Jiao
 * @date: 2018年11月17日
 */
@RestController
@RequestMapping(value = {"search/order", "/order"})
public class IOrderController {

    private final String INDEX = "runfast_order";

    private final String TYPE = "order";

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private ElasticsearchRepository<Object> elasticsearchRepository;

    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");

    @GetMapping(value = "/search")
    public WebResult search(HttpServletRequest request, @PageableDefault Pageable pageable) throws IOException {
        if((pageable.getOffset() + pageable.getPageSize()) > 1000000L){
            return WebResult.fail("查询结果集超出1000000行记录.");
        }
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        String agents = request.getParameter("agents");
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(StringUtil.isNotEmpty(agents)){
            boolQueryBuilder.must(QueryBuilders.termsQuery("agentId", agents.split(",")));
        }
        String orderNo = request.getParameter("orderNo");
        if(StringUtil.isNotEmpty(orderNo)){
            boolQueryBuilder.must(QueryBuilders.termQuery("orderCode", orderNo));
        }
        String busId = request.getParameter("busId");
        if(StringUtil.isNotEmpty(busId)){
            boolQueryBuilder.must(QueryBuilders.termQuery("businessId", busId));
        }
        String userMobile = request.getParameter("mobile");
        if(StringUtil.isNotEmpty(userMobile)){
            BoolQueryBuilder mobileQuery = QueryBuilders.boolQuery();
            mobileQuery.should(QueryBuilders.termQuery("userPhone", userMobile));
            mobileQuery.should(QueryBuilders.termQuery("userMobile", userMobile));
            boolQueryBuilder.must(mobileQuery);
        }
        String busName = request.getParameter("busName");
        if(StringUtil.isNotEmpty(busName)){
            boolQueryBuilder.must(QueryBuilders.prefixQuery("businessName", busName));
        }
        String starttime = request.getParameter("starttime");
        String endtime = request.getParameter("endtime");
        if(NumberUtils.isPositiveInteger(starttime) && NumberUtils.isPositiveInteger(endtime)){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime").from(starttime, true).to(endtime, true));
        }
        String status = request.getParameter("status");
        if(StringUtil.isNotEmpty(status)) {
            boolQueryBuilder.must(QueryBuilders.termsQuery("status", status.split(",")));
        }
        String userId = request.getParameter("userId");
        if(StringUtil.isNotEmpty(userId)){
            boolQueryBuilder.must(QueryBuilders.termQuery("userId", userId));
        }
        //拓展字段
        String expand_status = request.getParameter("expand_status");
        // 超时完成
        if("OUT_TIME_OVER".equalsIgnoreCase(expand_status)){
            Script script = new Script(ScriptType.STORED, null, "runfast_order_outtime_over", new HashMap<>());
            boolQueryBuilder.must(QueryBuilders.scriptQuery(script));
        }else if("EXISTS_REFUND".equalsIgnoreCase(expand_status)){
            //存在退款
            boolQueryBuilder.must(QueryBuilders.existsQuery("refund"));
        }else if("dispute_sheet".equalsIgnoreCase(expand_status)){
            //纠纷订单
            boolQueryBuilder.must(QueryBuilders.termQuery("dispute", 1));
        }else if("NEW_USER_ORDER".equalsIgnoreCase(expand_status)){
            //新用户下单
            boolQueryBuilder.must(QueryBuilders.termQuery("newUserOrder", 1));
        }

        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.size(pageable.getPageSize());
        sourceBuilder.from((int)pageable.getOffset());
        sourceBuilder.sort("createTime", SortOrder.DESC);
        searchRequest.source(sourceBuilder).indices(INDEX).types(TYPE);
        Page<Object> page = elasticsearchRepository.search(searchRequest, pageable);
        if(page != null){
            return WebResult.ok(page);
        }
        return WebResult.fail("查询失败");
    }


    /**
     * 调度台订单
     * @param request
     * @return
     * @throws IOException
     */
    @GetMapping(value = "/orderForDiaodu")
    public WebResult getOrderForDiaodu(HttpServletRequest request) throws IOException {
        String agentIdStr = request.getParameter("agentId");
        if(!NumberUtils.isPositiveInteger(agentIdStr)){
            return WebResult.fail("代理商ID错误");
        }
        Integer agentId = Integer.valueOf(agentIdStr);
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("unAppointed", this.getUnAppointed(agentId));
        resultMap.put("distribution", this.getDistribution(agentId));
        resultMap.put("abnormal", this.getAbnormal(agentId));
        resultMap.put("overtime", this.getOvertime(agentId));
        return WebResult.ok(resultMap);
    }

    /**
     * 待指派
     * @param agentId
     * @return
     * @throws IOException
     */
    private List<Object> getUnAppointed(Integer agentId) throws IOException {
        BoolQueryBuilder parentQueryBuilder = QueryBuilders.boolQuery();
        parentQueryBuilder.must(QueryBuilders.termQuery("agentId", agentId));
        parentQueryBuilder.must(QueryBuilders.termsQuery("status", new Integer[]{1,2}));
        parentQueryBuilder.must(QueryBuilders.boolQuery().should(QueryBuilders.termQuery("isCancel", 0)).should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("isCancel"))));
        parentQueryBuilder.must(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("isDeliver", 1)));
        parentQueryBuilder.must(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("suportSelf", true)));
        parentQueryBuilder.must(QueryBuilders.rangeQuery("createTime").from(DatesUtil.getBeginDayOfYesterday().getTime(), true).to(System.currentTimeMillis(), true));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.from(0).size(1000).query(parentQueryBuilder);
        SearchRequest request = new SearchRequest();
        request.source(sourceBuilder).indices(INDEX).types(TYPE);
        SearchResponse response = this.restHighLevelClient.search(request);
        return this.buildValues(response);
    }


    /**
     * 配送中
     * @param agentId
     * @return
     * @throws IOException
     */
    private List<Object> getDistribution(Integer agentId) throws IOException {
        BoolQueryBuilder parentQueryBuilder = QueryBuilders.boolQuery();
        parentQueryBuilder.must(QueryBuilders.termQuery("agentId", agentId));
        parentQueryBuilder.must(QueryBuilders.termsQuery("status", new Integer[]{3,4,5,6,7}));
        parentQueryBuilder.must(QueryBuilders.boolQuery().should(QueryBuilders.termQuery("isCancel", 0)).should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("isCancel"))));
        parentQueryBuilder.must(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("isDeliver", 1)));
        parentQueryBuilder.must(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("suportSelf", true)));
        parentQueryBuilder.must(QueryBuilders.rangeQuery("createTime").from(DatesUtil.getBeginDayOfYesterday().getTime(), true).to(System.currentTimeMillis(), true));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.from(0).size(1000).query(parentQueryBuilder);
        SearchRequest request = new SearchRequest();
        request.source(sourceBuilder).indices(INDEX).types(TYPE);
        SearchResponse response = this.restHighLevelClient.search(request);
        return this.buildValues(response);
    }


    /**
     *  异常
     * @param agentId
     * @return
     */
    private List<Object> getAbnormal(Integer agentId) throws IOException {
        BoolQueryBuilder parentQueryBuilder = QueryBuilders.boolQuery();
        parentQueryBuilder.must(QueryBuilders.termQuery("agentId", agentId));
        BoolQueryBuilder cancelQueryBuilder = QueryBuilders.boolQuery();
        cancelQueryBuilder.must(QueryBuilders.termQuery("isCancel", 1));
        cancelQueryBuilder.must(QueryBuilders.rangeQuery("status").from(2, true).to(7, true));
        BoolQueryBuilder refundQueryBuilder = QueryBuilders.boolQuery();
        refundQueryBuilder.must(QueryBuilders.termQuery("isRefund", 1));
        refundQueryBuilder.must(QueryBuilders.termQuery("status", 8));
        parentQueryBuilder.must(QueryBuilders.boolQuery().should(cancelQueryBuilder).should(refundQueryBuilder));
        parentQueryBuilder.must(QueryBuilders.rangeQuery("createTime").from(DatesUtil.getBeginDayOfYesterday().getTime(), true).to(System.currentTimeMillis(), true));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.from(0).size(1000).query(parentQueryBuilder);
        SearchRequest request = new SearchRequest();
        request.source(sourceBuilder).indices(INDEX).types(TYPE);
        SearchResponse response = this.restHighLevelClient.search(request);
        return this.buildValues(response);
    }


    /**
     * 超时完成
     * @param agentId
     * @return
     * @throws IOException
     */
    private List<Object> getOvertime(Integer agentId) throws IOException {
        BoolQueryBuilder parentQueryBuilder = QueryBuilders.boolQuery();
        parentQueryBuilder.must(QueryBuilders.termQuery("agentId", agentId));

        //超时完成
        Script script = new Script(ScriptType.STORED, null, "runfast_order_outtime_over", new HashMap<>());
        parentQueryBuilder.must(QueryBuilders.scriptQuery(script));

        parentQueryBuilder.must(QueryBuilders.rangeQuery("createTime").from(DatesUtil.getBeginDayOfYesterday().getTime(), true).to(System.currentTimeMillis(), true));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.from(0).size(1000).query(parentQueryBuilder);
        SearchRequest request = new SearchRequest();
        request.source(sourceBuilder).indices(INDEX).types(TYPE);
        SearchResponse response = this.restHighLevelClient.search(request);
        return this.buildValues(response);
    }


    private List buildValues(SearchResponse response){
        List<Object> values = new ArrayList<>();
        if(response.status() == RestStatus.OK){
            SearchHits searchHits = response.getHits();
            if(searchHits != null && searchHits.getHits() != null){
                SearchHit[] hits = searchHits.getHits();
                for(SearchHit hit : hits){
                    if(hit == null){
                        continue;
                    }
                    values.add(hit.getSourceAsMap());
                }
            }
        }
        return values;
    }
//    /**
//     * 统计
//     * @return
//     */
//    @GetMapping(value = "/statistical")
//    public WebResult<List<SellRecordStatistical>> getStatistical(HttpServletRequest request) throws IOException {
//        String[] agents = request.getParameterValues("agents");
//        String starttime = request.getParameter("starttime");
//        String endtime = request.getParameter("endtime");
//        String timeFormatPattern = "yyyy-MM-dd HH";
//        SearchRequest searchRequest = new SearchRequest();
//        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//        BoolQueryBuilder qbs = QueryBuilders.boolQuery();
//        if(agents != null && agents.length > 0){
//            qbs.must(QueryBuilders.termsQuery("agentId", agents));
//        }
//        if(NumberUtils.isPositiveInteger(starttime) && NumberUtils.isPositiveInteger(endtime)){
//            long startTime = Long.parseLong(starttime);
//            long endTime = Long.parseLong(endtime);
//            if(startTime > endTime){
//                return WebResult.fail("开始时间必须大于结束时间");
//            }else if(startTime - endTime > 5356800000L){
//                return WebResult.fail("统计时间范围在2个月以内");
//            }
//            qbs.must(QueryBuilders.rangeQuery("createTime").gte(startTime));
//            qbs.must(QueryBuilders.rangeQuery("createTime").lte(endTime));
//        }
//        //完成的订单
//        qbs.must(QueryBuilders.termQuery("status", 8));
//        qbs.must(QueryBuilders.termQuery("isPay", 1));
//        sourceBuilder.query(qbs);
//        DateHistogramAggregationBuilder timeBuilder = AggregationBuilders.dateHistogram("agg_create_time").field("createTime").dateHistogramInterval(DateHistogramInterval.hours(1)).format(timeFormatPattern);
//        TermsAggregationBuilder payTypeBuilder = AggregationBuilders.terms("agg_pay_type").field("payType");
//        TermsAggregationBuilder isDeliverBuilder = AggregationBuilders.terms("agg_is_deliver").field("isDeliver");
//        TermsAggregationBuilder loginOnBuilder = AggregationBuilders.terms("agg_login_on").field("loginOn");
//        //聚合查询
//        SumAggregationBuilder totalPay = AggregationBuilders.sum("agg_totalpay").field("totalpay");
//        SumAggregationBuilder totalRefund = AggregationBuilders.sum("agg_refund").field("refund");
//        SumAggregationBuilder goodsTotal = AggregationBuilders.sum("agg_goods_total").field("goodsTotal");
//        SumAggregationBuilder activityprice = AggregationBuilders.sum("agg_activityprice").field("activityprice");
//        SumAggregationBuilder subsidy = AggregationBuilders.sum("agg_subsidy").field("subsidy");
//        SumAggregationBuilder showps = AggregationBuilders.sum("agg_showps").field("showps");
//        SumAggregationBuilder agentBusget = AggregationBuilders.sum("agg_agent_busget").field("agentBusget");
//        AggregationBuilder aggregationBuilder = loginOnBuilder.subAggregation(totalPay).subAggregation(totalRefund).subAggregation(goodsTotal).subAggregation(activityprice).subAggregation(subsidy).subAggregation(showps).subAggregation(agentBusget);
//        sourceBuilder.aggregation(timeBuilder.subAggregation(payTypeBuilder.subAggregation(isDeliverBuilder.subAggregation(aggregationBuilder))));
//        searchRequest.indices(INDEX).source(sourceBuilder);
//        System.out.println(searchRequest.source());
//        SearchResponse response = restHighLevelClient.search(searchRequest);
//        RestStatus restStatus = response.status();
//        if(restStatus == null){
//            return WebResult.fail("查询失败");
//        }else if(restStatus != RestStatus.OK){
//            return WebResult.fail("搜索服务请求失败.");
//        }else {
//            List<SellRecordStatistical> recordStatisticals = new ArrayList<>();
//            Aggregations agg = response.getAggregations();
//            Histogram histogram = agg.get("agg_create_time");
//            SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormatPattern);
//            for (Histogram.Bucket entry : histogram.getBuckets()) {
//                String timer = entry.getKeyAsString();
//                ParsePosition pos = new ParsePosition(0);
//                //订单时间(记录到小时)
//                Date orderHour = dateFormat.parse(timer, pos);
//                Terms payTypTerms = entry.getAggregations().get("agg_pay_type");
//                for(Terms.Bucket pbucket : payTypTerms.getBuckets()){
//                    //支付方式
//                    int paytype = pbucket.getKeyAsNumber().intValue();
//                    Terms delyverLongTerms = pbucket.getAggregations().get("agg_is_deliver");
//                    for(Terms.Bucket deliverBucket : delyverLongTerms.getBuckets()){
//                        //配送方式
//                        int deliver = deliverBucket.getKeyAsNumber().intValue();
//                        Terms loginOnTerms = deliverBucket.getAggregations().get("agg_login_on");
//                        for(Terms.Bucket bucket : loginOnTerms.getBuckets()){
//                            //登陆方式
//                            int loginOn = bucket.getKeyAsNumber().intValue();
//                            Sum agg_totalpay = bucket.getAggregations().get("agg_totalpay");
//                            Sum agg_refund = bucket.getAggregations().get("agg_refund");
//                            Sum agg_goods_total = bucket.getAggregations().get("agg_goods_total");
//                            Sum agg_activityprice = bucket.getAggregations().get("agg_activityprice");
//                            Sum agg_subsidy = bucket.getAggregations().get("agg_subsidy");
//                            Sum agg_showps = bucket.getAggregations().get("agg_showps");
//                            Sum agg_agent_busget = bucket.getAggregations().get("agg_agent_busget");
//
//                            SellRecordStatistical statistical = new SellRecordStatistical();
//                            statistical.setTime(orderHour);
//                            statistical.setActivityprice(BigDecimal.valueOf(agg_activityprice.getValue()));
//                            statistical.setAgentBusget(BigDecimal.valueOf(agg_agent_busget.getValue()));
//                            statistical.setGoodstotal((int) agg_goods_total.getValue());
//                            statistical.setRefund(BigDecimal.valueOf(agg_refund.getValue()));
//                            statistical.setTotalpay(BigDecimal.valueOf(agg_totalpay.getValue()));
//                            statistical.setSubsidy(BigDecimal.valueOf(agg_subsidy.getValue()));
//                            statistical.setShowps(BigDecimal.valueOf(agg_showps.getValue()));
//                            statistical.setLoginOn(loginOn);
//                            statistical.setIsDeliver(deliver);
//                            statistical.setPaytype(paytype);
//                            statistical.setQuantity((int)bucket.getDocCount());
//                            recordStatisticals.add(statistical);
//                        }
//                    }
//                }
//            }
//            return WebResult.ok("ok", recordStatisticals);
//        }
//    }

    /**
     * 统计
     * @return
     */
    @GetMapping(value = "/statistical")
    public WebResult<Object> getStatistical(HttpServletRequest request) throws IOException {
        String agents = request.getParameter("agents");
        WebResult webResult = this.getDayStatistical(agents == null ? null : agents.split(","));
        if(webResult.getStatus() != WebStatus.SUCCESS){
            return webResult;
        }
        Object hourStatistical =  webResult.getData();
        WebResult monthResult = this.getMonthStatistical(agents == null ? null : agents.split(","));
        if(monthResult.getStatus() != WebStatus.SUCCESS){
            return monthResult;
        }
        Object monthStatistical = monthResult.getData();
        Map<String,Object> map = new HashMap<>();
        map.put("byhour", hourStatistical);
        map.put("byday", monthStatistical);
        return WebResult.ok(map);
    }

    /**
     * 获取昨日/今日配送数据
     * @param agents
     * @return
     */
    private WebResult<Contrast<Statistical>> getDayStatistical(String[] agents) throws IOException {
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder qbs = QueryBuilders.boolQuery();
        if(agents != null && agents.length > 0) {
            qbs.must(QueryBuilders.termsQuery("agentId", agents));
        }
        qbs.must(QueryBuilders.termQuery("status", 8));
        qbs.must(QueryBuilders.termQuery("isPay", 1));
        Date endDate = DatesUtil.getDayEnd();
        Date startDate = DatesUtil.getBeginDayOfYesterday();
        //订单时间(记录到小时)
        qbs.must(QueryBuilders.rangeQuery("createTime").from(startDate.getTime(), true).to(endDate.getTime(), true));
        sourceBuilder.query(qbs);
        DateHistogramAggregationBuilder timeBuilder = AggregationBuilders.dateHistogram("agg_create_time").field("createTime").dateHistogramInterval(DateHistogramInterval.hours(1)).timeZone(DateTimeZone.forID("Asia/Shanghai"));
        TermsAggregationBuilder payTypeBuilder = AggregationBuilders.terms("agg_pay_type").field("payType");
        TermsAggregationBuilder isDeliverBuilder = AggregationBuilders.terms("agg_is_deliver").field("isDeliver");
        TermsAggregationBuilder loginOnBuilder = AggregationBuilders.terms("agg_login_on").field("loginOn");
        //聚合查询
        SumAggregationBuilder totalPay = AggregationBuilders.sum("agg_totalpay").field("totalpay");
        ////.field("refund");
        SumAggregationBuilder totalRefund = AggregationBuilders.sum("agg_refund").script(new Script(ScriptType.STORED, null,"runfast_order_format_refund", new HashMap<>()));
        SumAggregationBuilder activityprice = AggregationBuilders.sum("agg_activityprice").field("activityprice");
        SumAggregationBuilder subsidy = AggregationBuilders.sum("agg_subsidy").field("subsidy");
        SumAggregationBuilder showps = AggregationBuilders.sum("agg_showps").field("showps");
        SumAggregationBuilder agentBusget = AggregationBuilders.sum("agg_agent_busget").field("agentBusget");
        AggregationBuilder aggregationBuilder = loginOnBuilder.subAggregation(totalPay).subAggregation(totalRefund).subAggregation(activityprice).subAggregation(subsidy).subAggregation(showps).subAggregation(agentBusget);
        sourceBuilder.aggregation(timeBuilder.subAggregation(payTypeBuilder.subAggregation(isDeliverBuilder.subAggregation(aggregationBuilder))));
        sourceBuilder.from(0).size(0);
        searchRequest.indices(INDEX).source(sourceBuilder).types(TYPE);
        SearchResponse response = restHighLevelClient.search(searchRequest);
        RestStatus restStatus = response.status();
        if(restStatus == null){
            return WebResult.fail("查询失败");
        }else if(restStatus != RestStatus.OK){
            return WebResult.fail("搜索服务请求失败.");
        }else {
            Contrast<Statistical> contrast = new Contrast();
            contrast._last = new Statistical();
            contrast._this = new Statistical();
            Aggregations agg = response.getAggregations();
            Histogram histogram = agg.get("agg_create_time");
            for (Histogram.Bucket entry : histogram.getBuckets()) {
                String timer = entry.getKeyAsString();
                //订单时间(记录到小时)
                ParsePosition pos = new ParsePosition(0);
                Date orderHour = dateFormat.parse(timer, pos);
                Terms payTypTerms = entry.getAggregations().get("agg_pay_type");
                for (Terms.Bucket pbucket : payTypTerms.getBuckets()) {
                    //支付方式
                    int paytype = pbucket.getKeyAsNumber().intValue();
                    Terms delyverLongTerms = pbucket.getAggregations().get("agg_is_deliver");
                    for (Terms.Bucket deliverBucket : delyverLongTerms.getBuckets()) {
                        //配送方式
                        int deliver = deliverBucket.getKeyAsNumber().intValue();
                        Terms loginOnTerms = deliverBucket.getAggregations().get("agg_login_on");
                        for (Terms.Bucket bucket : loginOnTerms.getBuckets()) {
                            //登陆方式
                            int loginOn = bucket.getKeyAsNumber().intValue();
                            Sum agg_totalpay = bucket.getAggregations().get("agg_totalpay");
                            Sum agg_refund = bucket.getAggregations().get("agg_refund");
                            Sum agg_activityprice = bucket.getAggregations().get("agg_activityprice");
                            Sum agg_subsidy = bucket.getAggregations().get("agg_subsidy");
                            Sum agg_showps = bucket.getAggregations().get("agg_showps");
                            Sum agg_agent_busget = bucket.getAggregations().get("agg_agent_busget");
                            if(DatesUtil.isToday(orderHour)){
                                contrast._this.add(MyUtil.getHourOfDay(orderHour), (int) bucket.getDocCount(), BigDecimal.valueOf(agg_activityprice.getValue()),
                                        BigDecimal.valueOf(agg_agent_busget.getValue()), BigDecimal.valueOf(agg_refund.getValue()), BigDecimal.valueOf(agg_totalpay.getValue()),
                                        BigDecimal.valueOf(agg_subsidy.getValue()), BigDecimal.valueOf(agg_showps.getValue()), paytype, loginOn, deliver);
                            }else if(DatesUtil.isYesterday(orderHour)){
                                contrast._last.add(MyUtil.getHourOfDay(orderHour), (int) bucket.getDocCount(), BigDecimal.valueOf(agg_activityprice.getValue()),
                                        BigDecimal.valueOf(agg_agent_busget.getValue()), BigDecimal.valueOf(agg_refund.getValue()), BigDecimal.valueOf(agg_totalpay.getValue()),
                                        BigDecimal.valueOf(agg_subsidy.getValue()), BigDecimal.valueOf(agg_showps.getValue()), paytype, loginOn, deliver);
                            }else{
                                System.out.println(timer);
                            }
                        }
                    }
                }
            }
            for(Integer i = 0; i <= 23; i++){
                if(!contrast._this.hoursQun.containsKey(i)){
                    contrast._this.hoursQun.put(i, 0);
                }
                if(!contrast._this.hoursAmount.containsKey(i)){
                    contrast._this.hoursAmount.put(i, BigDecimal.valueOf(0));
                }
                if(!contrast._last.hoursQun.containsKey(i)){
                    contrast._last.hoursQun.put(i, 0);
                }
                if(!contrast._last.hoursAmount.containsKey(i)){
                    contrast._last.hoursAmount.put(i, BigDecimal.valueOf(0));
                }
            }
            return WebResult.ok(contrast);
        }
    }


    @GetMapping(value = "/yesterOrderQuantityInfo")
    private WebResult<Object> getYesterOrderQuantityInfo(String[] agents) throws IOException {
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder parentQueryBuilder = QueryBuilders.boolQuery();
        parentQueryBuilder.must(QueryBuilders.rangeQuery("createTime").from(DatesUtil.getBeginDayOfYesterday(), true).to(DatesUtil.getEndDayOfYesterDay(), true));
        parentQueryBuilder.must(QueryBuilders.termsQuery("status", new String[]{"-1", "8"}));
        if(agents != null && agents.length > 0){
            parentQueryBuilder.must(QueryBuilders.termsQuery("agentId", agents));
        }
        SumAggregationBuilder outtime_overQuantity = AggregationBuilders.sum("agg_outtime_over_count").script(new Script(ScriptType.STORED, null, "runfast_order_outtime_over_sum", new HashMap<>()));
        SumAggregationBuilder outtime_overAmount = AggregationBuilders.sum("agg_outtime_over_amount").script(new Script(ScriptType.STORED, null, "runfast_order_outtime_over_amount", new HashMap<>()));
        SumAggregationBuilder cancel_sum = AggregationBuilders.sum("agg_cancelCount").script(new Script(ScriptType.STORED, null, "runfast_order_cancel_sum", new HashMap<>()));
        SumAggregationBuilder cancel_amount = AggregationBuilders.sum("agg_cancelAmount").script(new Script(ScriptType.STORED, null, "runfast_order_cancel_amount", new HashMap<>()));
        Map<String,Object> newUserParamMap = new HashMap<>();
        if(agents != null && agents.length > 0){
            newUserParamMap.put("new1", 1);
        }else{
            newUserParamMap.put("new1", 2);
        }
        SumAggregationBuilder new_user_sum = AggregationBuilders.sum("agg_runfast_order_new_user_sum").script(new Script(ScriptType.STORED, null, "runfast_order_new_user_sum", newUserParamMap));
        SumAggregationBuilder new_user_amount = AggregationBuilders.sum("agg_runfast_order_new_user_amount").script(new Script(ScriptType.STORED, null, "runfast_order_new_user_amount", newUserParamMap));
        SumAggregationBuilder negative_sum = AggregationBuilders.sum("agg_runfast_order_negative_sum").script(new Script(ScriptType.STORED, null, "runfast_order_negative_count", new HashMap<>()));
        SumAggregationBuilder negative_amount = AggregationBuilders.sum("agg_runfast_order_negative_amount").script(new Script(ScriptType.STORED, null, "runfast_order_negative_amount", new HashMap<>()));
        ValueCountAggregationBuilder agg_total = AggregationBuilders.count("total").field("id");
        sourceBuilder.aggregation(outtime_overQuantity).aggregation(outtime_overAmount).aggregation(cancel_sum).aggregation(cancel_amount).aggregation(new_user_sum).aggregation(new_user_amount)
                .aggregation(negative_sum).aggregation(negative_amount).aggregation(agg_total);

        sourceBuilder.query(parentQueryBuilder);
        sourceBuilder.from(0).size(0);
        searchRequest.source(sourceBuilder).indices(INDEX).types(TYPE);
        System.out.println(searchRequest.source());
        SearchResponse response = restHighLevelClient.search(searchRequest);
        RestStatus status = response.status();
        if(status == RestStatus.OK) {
            Aggregations agg = response.getAggregations();
            Sum outtimeQuantity = agg.get("agg_outtime_over_count");
            Sum outtimeAmount = agg.get("agg_outtime_over_amount");
            Sum cancelCount = agg.get("agg_cancelCount");
            Sum cancelAmount = agg.get("agg_cancelAmount");
            Sum newUserSum = agg.get("agg_runfast_order_new_user_sum");
            Sum newUserAmount = agg.get("agg_runfast_order_new_user_amount");
            Sum negativeSum = agg.get("agg_runfast_order_negative_sum");
            Sum negativeAmount = agg.get("agg_runfast_order_negative_amount");
            ValueCount total = agg.get("total");
            Long totalCount = null;
            if(total != null){
                totalCount = total.getValue();
            }else{
                totalCount = 0L;
            }
//            //新用户下单
            return WebResult.ok(this.yesOrInfo((int)outtimeQuantity.getValue(), this.formatAmoumt(outtimeAmount.getValue()),
                    (int) cancelCount.getValue(), this.formatAmoumt(cancelAmount.getValue()),
                    (int) newUserSum.getValue(), this.formatAmoumt(newUserAmount.getValue()),
                    (int) negativeSum.getValue(), this.formatAmoumt(negativeAmount.getValue()), totalCount));
        }
        return WebResult.fail("查询失败.");
    }

    private BigDecimal formatAmoumt(double val){
        return BigDecimal.valueOf(val).setScale(2,BigDecimal.ROUND_HALF_UP);
    }

    private Object yesOrInfo(Object overtimeQuantity,Object overtimeAmount, Object cancelQuantity, Object cancelAmount,
                             Object newCustomerQuantity, Object newCustomerAmount, Object negativeCommentQuantity,
                             Object negativeCommentAmount,Long total){
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("overtimeQuantity", overtimeQuantity);
        resultMap.put("overtimeAmount", overtimeAmount);
        resultMap.put("cancelQuantity", cancelQuantity);
        resultMap.put("cancelAmount", cancelAmount);
        resultMap.put("newCustomerQuantity", newCustomerQuantity);
        resultMap.put("newCustomerAmount", newCustomerAmount);
        resultMap.put("negativeCommentQuantity", negativeCommentQuantity);
        resultMap.put("negativeCommentAmount", negativeCommentAmount);
        resultMap.put("cancelAndOverOrderCount", total);
        return resultMap;
    }

    /**
     * 统计上月本月数据
     * @param agents
     * @return
     */
    private WebResult<Object> getMonthStatistical(String[] agents) throws IOException {
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder qbs = QueryBuilders.boolQuery();
        if(agents != null && agents.length > 0) {
            qbs.must(QueryBuilders.termsQuery("agentId", agents));
        }
        qbs.must(QueryBuilders.termQuery("status", 8));
        qbs.must(QueryBuilders.termQuery("isPay", 1));
        Date endDate = DatesUtil.getDayEnd();
        Date startDate = DatesUtil.getBeginDayOfLastMonth();
        qbs.must(QueryBuilders.rangeQuery("createTime").from(startDate.getTime(), true).to(endDate.getTime(), true));
        sourceBuilder.query(qbs);
        DateHistogramAggregationBuilder timeBuilder = AggregationBuilders.dateHistogram("agg_create_time").field("createTime").dateHistogramInterval(DateHistogramInterval.days(1)).timeZone(DateTimeZone.forID("Asia/Shanghai"));
        //聚合查询
        SumAggregationBuilder totalPay = AggregationBuilders.sum("agg_totalpay").field("totalpay");
        SumAggregationBuilder totalRefund = AggregationBuilders.sum("agg_refund").script(new Script(ScriptType.STORED, null,"runfast_order_format_refund", new HashMap<>()));
        AggregationBuilder aggregationBuilder = timeBuilder.subAggregation(totalPay).subAggregation(totalRefund);
        sourceBuilder.aggregation(aggregationBuilder);
        sourceBuilder.from(0).size(0);
        searchRequest.indices(INDEX).source(sourceBuilder).types(TYPE);
        SearchResponse response = restHighLevelClient.search(searchRequest);
        RestStatus restStatus = response.status();
        if(restStatus == null){
            return WebResult.fail("查询失败");
        }else if(restStatus != RestStatus.OK){
            return WebResult.fail("搜索服务请求失败.");
        }else {
            Map<Integer,Map<String,Object>> lastWeek = new HashMap<>();
            Map<Integer,Map<String,Object>> thisWeek = new HashMap<>();
            Map<Integer,Map<String,Object>> lastMonth = new HashMap<>();
            Map<Integer,Map<String,Object>> thisMonth = new HashMap<>();
            Aggregations agg = response.getAggregations();
            Histogram histogram = agg.get("agg_create_time");
            for (Histogram.Bucket entry : histogram.getBuckets()) {
                String timer = entry.getKeyAsString();
                //订单时间(记录到小时)
                ParsePosition pos = new ParsePosition(0);
                Date time = dateFormat.parse(timer, pos);
                Sum agg_totalpay = entry.getAggregations().get("agg_totalpay");
                Sum agg_refund = entry.getAggregations().get("agg_refund");
                BigDecimal refund = BigDecimal.valueOf(agg_refund.getValue());
                BigDecimal _totalPay = BigDecimal.valueOf(agg_totalpay.getValue());
                BigDecimal actualTotalPay = null;
                if(refund == null || refund.compareTo(BigDecimal.ZERO) == 0) {
                    actualTotalPay = _totalPay;
                }else{
                    actualTotalPay = _totalPay.subtract(refund);
                }
                Map<String,Object> sticItem = this.initDayItem((int)entry.getDocCount(), actualTotalPay);
                if(DatesUtil.isLastmonth(time)){
                    lastMonth.put(MyUtil.getDayOfMonth(time), sticItem);
                }else if(DatesUtil.isThismonth(time)){
                    thisMonth.put(MyUtil.getDayOfMonth(time), sticItem);
                }

                if(DatesUtil.isLastweek(time)){
                    lastWeek.put(MyUtil.getDayOfWeek(time), sticItem);
                }else if(DatesUtil.isThisweek(time)){
                    int dayOfWeek = MyUtil.getDayOfWeek(time);
                    if(thisWeek.containsKey(String.valueOf(dayOfWeek))){
                        System.out.println("遗漏掉的数据");
                    }else {
                        thisWeek.put(dayOfWeek, sticItem);
                    }
                }
            }
            //填充数据
            for(Integer i = 1; i <= 31; i++){
                if(i < 8) {
                    if (!lastWeek.containsKey(i)) {
                        lastWeek.put(i, this.initDayItem(0, BigDecimal.valueOf(0)));
                    }
                    if (!thisWeek.containsKey(i)) {
                        thisWeek.put(i, this.initDayItem(0, BigDecimal.valueOf(0)));
                    }
                }
                if(!thisMonth.containsKey(i)){
                    thisMonth.put(i, this.initDayItem(0, BigDecimal.valueOf(0)));
                }
                if(!lastMonth.containsKey(i)){
                    lastMonth.put(i, this.initDayItem(0, BigDecimal.valueOf(0)));
                }
            }
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("thisWeek", thisWeek);
            resultMap.put("lastWeek", lastWeek);
            resultMap.put("lastMonth", lastMonth);
            resultMap.put("thisMonth", thisMonth);
            return WebResult.ok(resultMap);
        }
    }

    /**
     * 商家销量排行
     * @param agentId
     * @param topSize
     * @return
     * @throws IOException
     */
    @GetMapping(value = "/businessTop")
    public WebResult<Object> getBusinessTopList(Integer agentId, @RequestParam(required = true, defaultValue = "15") Integer topSize) throws IOException {
        if(agentId == null){
            return WebResult.fail("代理商ID错误");
        }
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder qbs = QueryBuilders.boolQuery();
        qbs.must(QueryBuilders.termQuery("agentId", agentId));
        qbs.must(QueryBuilders.termQuery("status", 8));
        qbs.must(QueryBuilders.termQuery("isPay", 1));
        Date endDate = DatesUtil.getEndDayOfYesterDay();
        Date startDate = DatesUtil.getBeginDayOfYesterday();
        qbs.must(QueryBuilders.rangeQuery("createTime").from(startDate, true).to(endDate, true));
        TermsAggregationBuilder payTypeBuilder = AggregationBuilders.terms("agg_busId").field("businessId").order(Terms.Order.aggregation("agg_totalpay", false)).size(topSize);
        SumAggregationBuilder totalPay = AggregationBuilders.sum("agg_totalpay").script(new Script(ScriptType.STORED, null, "runfast_order_actual_patyamount", new HashMap<>()));
        sourceBuilder.aggregation(payTypeBuilder.subAggregation(totalPay)).query(qbs);
        sourceBuilder.from(0).size(0);
        searchRequest.indices(INDEX).types(TYPE).source(sourceBuilder);
        SearchResponse response = restHighLevelClient.search(searchRequest);
        if(response.status() == null){
            return WebResult.fail("查询失败");
        }else if(response.status() != RestStatus.OK){
            return WebResult.fail("搜索服务请求失败.");
        }else {
            List<Object> objects = new ArrayList<>();
            Aggregations aggregations = response.getAggregations();
            Terms terms = aggregations.get("agg_busId");
            for(Terms.Bucket bucket : terms.getBuckets()){
                String busId = bucket.getKeyAsString();
                Sum agg_totalpay =  bucket.getAggregations().get("agg_totalpay");
                Map<String,Object> busTop = new HashMap<>();
                BigDecimal _totalPay = BigDecimal.valueOf(agg_totalpay.getValue()).setScale(2,BigDecimal.ROUND_HALF_UP);
                busTop.put("amount", _totalPay);
                busTop.put("quantity", bucket.getDocCount());
                busTop.put("busId", busId);
                objects.add(busTop);
            }
            return WebResult.ok(objects);
        }
    }


    /**
     * 商家订单量排行
     * @param agentId
     * @param topSize
     * @return
     * @throws IOException
     */
    @GetMapping(value = "/businessTopByQuantity")
    public WebResult<Object> getBusinessTopListByQuantity(Integer agentId, @RequestParam(required = true, defaultValue = "15") Integer topSize) throws IOException {
        if(agentId == null){
            return WebResult.fail("代理商ID错误");
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        SearchRequest searchRequest = new SearchRequest();
        BoolQueryBuilder qbs = QueryBuilders.boolQuery();
        qbs.must(QueryBuilders.termQuery("agentId", agentId));
        qbs.must(QueryBuilders.termQuery("status", 8));
        qbs.must(QueryBuilders.termQuery("isPay", 1));
        Date endDate = DatesUtil.getEndDayOfYesterDay();
        Date startDate = DatesUtil.getBeginDayOfYesterday();
        qbs.must(QueryBuilders.rangeQuery("createTime").from(startDate, true).to(endDate, true));
        TermsAggregationBuilder payTypeBuilder = AggregationBuilders.terms("agg_busId").field("businessId").order(Terms.Order.count(false)).size(topSize);
        SumAggregationBuilder totalPay = AggregationBuilders.sum("agg_totalpay").script(new Script(ScriptType.STORED, null, "runfast_order_actual_patyamount", new HashMap<>()));
        sourceBuilder.aggregation(payTypeBuilder.subAggregation(totalPay)).query(qbs);
        sourceBuilder.from(0).size(0);
        searchRequest.indices(INDEX).types(TYPE).source(sourceBuilder);
        SearchResponse response = restHighLevelClient.search(searchRequest);
        if(response.status() == null){
            return WebResult.fail("查询失败");
        }else if(response.status() != RestStatus.OK){
            return WebResult.fail("搜索服务请求失败.");
        }else {
            Aggregations aggregations = response.getAggregations();
            Terms terms = aggregations.get("agg_busId");
            List<Object> objects = new ArrayList<>();
            for(Terms.Bucket bucket : terms.getBuckets()){
                Sum agg_totalpay =  bucket.getAggregations().get("agg_totalpay");
                Map<String,Object> busTop = new HashMap<>();
                String busId = bucket.getKeyAsString();
                BigDecimal _totalPay = BigDecimal.valueOf(agg_totalpay.getValue()).setScale(2,BigDecimal.ROUND_HALF_UP);
                busTop.put("busId", busId);
                busTop.put("quantity", bucket.getDocCount());
                busTop.put("amount", _totalPay);
                objects.add(busTop);
            }
            return WebResult.ok(objects);
        }
    }


    /**
     * 代理商销量排行
     * @param topSize
     * @return
     * @throws IOException
     */
    @GetMapping(value = "/agentBusTop")
    public WebResult<Object> getAgentBusTopList(@RequestParam(required = true, defaultValue = "15") Integer topSize, HttpServletRequest request) throws IOException {
        String agents = request.getParameter("agents");
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder qbs = QueryBuilders.boolQuery();
        if(agents != null && StringUtil.isNotEmpty(agents)) {
            qbs.must(QueryBuilders.termsQuery("agentId", agents.split(",")));
        }
        qbs.must(QueryBuilders.termQuery("status", 8));
        qbs.must(QueryBuilders.termQuery("isPay", 1));
        Date endDate = DatesUtil.getEndDayOfYesterDay();
        Date startDate = DatesUtil.getBeginDayOfYesterday();
        qbs.must(QueryBuilders.rangeQuery("createTime").from(startDate, true).to(endDate, true));
        TermsAggregationBuilder payTypeBuilder = AggregationBuilders.terms("agg_agentId").field("agentId").order(Terms.Order.aggregation("agg_totalpay", false)).size(topSize);
        SumAggregationBuilder totalPay = AggregationBuilders.sum("agg_totalpay").script(new Script(ScriptType.STORED, null, "runfast_order_actual_patyamount", new HashMap<>()));
        sourceBuilder.aggregation(payTypeBuilder.subAggregation(totalPay)).query(qbs);
        sourceBuilder.from(0).size(0);
        searchRequest.indices(INDEX).source(sourceBuilder).types(TYPE);
        System.out.println(searchRequest.source());
        SearchResponse response = restHighLevelClient.search(searchRequest);
        if(response.status() == null){
            return WebResult.fail("查询失败");
        }else if(response.status() != RestStatus.OK){
            return WebResult.fail("搜索服务请求失败.");
        }else {
            List<Object> top = new ArrayList<>();
            Aggregations aggregations = response.getAggregations();
            Terms terms = aggregations.get("agg_agentId");
            for(Terms.Bucket bucket : terms.getBuckets()){
                Map<String,Object> busTop = new HashMap<>();
                String agentId = bucket.getKeyAsString();
                Sum agg_totalpay =  bucket.getAggregations().get("agg_totalpay");
                BigDecimal _totalPay = BigDecimal.valueOf(agg_totalpay.getValue()).setScale(2,BigDecimal.ROUND_HALF_UP);
                busTop.put("amount", _totalPay);
                busTop.put("quantity", bucket.getDocCount());
                busTop.put("agentId", agentId);
                top.add(busTop);
            }
            return WebResult.ok(top);
        }
    }


    /**
     * 代理商订单量排行
     * @param topSize
     * @return
     * @throws IOException
     */
    @GetMapping(value = "/agentBusTopByQuantity")
    public WebResult<Object> getAgentBusTopListByQuantity(@RequestParam(required = true, defaultValue = "15") Integer topSize, HttpServletRequest request) throws IOException {
        String agents = request.getParameter("agents");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        SearchRequest searchRequest = new SearchRequest();
        BoolQueryBuilder qbs = QueryBuilders.boolQuery();
        if(agents != null && StringUtil.isNotEmpty(agents)) {
            qbs.must(QueryBuilders.termsQuery("agentId", agents.split(",")));
        }
        qbs.must(QueryBuilders.termQuery("status", 8));
        qbs.must(QueryBuilders.termQuery("isPay", 1));
        Date endDate = DatesUtil.getEndDayOfYesterDay();
        Date startDate = DatesUtil.getBeginDayOfYesterday();
        qbs.must(QueryBuilders.rangeQuery("createTime").from(startDate, true).to(endDate, true));
        TermsAggregationBuilder payTypeBuilder = AggregationBuilders.terms("agg_agentId").field("agentId").order(Terms.Order.count(false)).size(topSize);
        SumAggregationBuilder totalPay = AggregationBuilders.sum("agg_totalpay").script(new Script(ScriptType.STORED, null, "runfast_order_actual_patyamount", new HashMap<>()));
        sourceBuilder.aggregation(payTypeBuilder.subAggregation(totalPay)).query(qbs);
        sourceBuilder.from(0).size(0);
        searchRequest.indices(INDEX).source(sourceBuilder).types(TYPE);
        System.out.println(searchRequest.source());
        SearchResponse response = restHighLevelClient.search(searchRequest);
        if(response.status() == null || response.status() != RestStatus.OK){
            return WebResult.fail("查询失败");
        }else {
            Aggregations aggregations = response.getAggregations();
            Terms terms = aggregations.get("agg_agentId");
            List<Object> top = new ArrayList<>();
            for(Terms.Bucket bucket : terms.getBuckets()){
                Map<String,Object> busTop = new HashMap<>();
                String agentId = bucket.getKeyAsString();
                Sum agg_totalpay =  bucket.getAggregations().get("agg_totalpay");
                BigDecimal _totalPay = BigDecimal.valueOf(agg_totalpay.getValue()).setScale(2,BigDecimal.ROUND_HALF_UP);
                busTop.put("agentId", agentId);
                busTop.put("amount", _totalPay);
                busTop.put("quantity", bucket.getDocCount());
                top.add(busTop);
            }
            return WebResult.ok(top);
        }
    }


    @GetMapping(value = "/shopperTop")
    public WebResult<Object> getShopperTopList(@RequestParam(required = true, defaultValue = "15") Integer topSize, HttpServletRequest request) throws IOException {
        String agentId = request.getParameter("agentId");
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder qbs = QueryBuilders.boolQuery();
        if(NumberUtils.isPositiveInteger(agentId)) {
            qbs.must(QueryBuilders.termsQuery("agentId", agentId));
        }
        String agents = request.getParameter("agents");

        if(StringUtil.isNotEmpty(agents)){
            qbs.must(QueryBuilders.termsQuery("agentId", agents.split(",")));
        }

        qbs.must(QueryBuilders.termQuery("status", 8));
        qbs.must(QueryBuilders.termQuery("isPay", 1));
        BoolQueryBuilder deliverQbs = QueryBuilders.boolQuery();
        deliverQbs.should(QueryBuilders.termQuery("isDeliver", 0));
        deliverQbs.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("isDeliver")));
        qbs.must(deliverQbs);
        qbs.must(QueryBuilders.existsQuery("shopperId"));
        Date endDate = DatesUtil.getEndDayOfYesterDay();
        Date startDate = DatesUtil.getBeginDayOfYesterday();
        qbs.must(QueryBuilders.rangeQuery("createTime").from(startDate, true).to(endDate, true));
        TermsAggregationBuilder shopperIdBuilder = AggregationBuilders.terms("agg_shopperId").field("shopperId").order(Terms.Order.count(false)).size(topSize);
        SumAggregationBuilder agg_outtime_over = AggregationBuilders.sum("agg_outtime_over").script(new Script(ScriptType.STORED,null,"runfast_order_outtime_over_sum", new HashMap<>()));
        ValueCountAggregationBuilder agg_total_count = AggregationBuilders.count("agg_total_count").field("id");
        sourceBuilder.aggregation(shopperIdBuilder.subAggregation(agg_outtime_over).subAggregation(agg_total_count)).query(qbs);
        sourceBuilder.from(0).size(0);
        searchRequest.indices(INDEX).source(sourceBuilder).types(TYPE);
        System.out.println(searchRequest.source());
        SearchResponse response = restHighLevelClient.search(searchRequest);
        if(response.status() == null){
            return WebResult.fail("查询失败");
        }else if(response.status() != RestStatus.OK){
            return WebResult.fail("搜索服务请求失败.");
        }else {
            List<Object> objects = new ArrayList<>();
            Aggregations aggregations = response.getAggregations();
            Terms terms = aggregations.get("agg_shopperId");
            for(Terms.Bucket bucket : terms.getBuckets()){
                String shopperId = bucket.getKeyAsString();
                Sum outtime_over =  bucket.getAggregations().get("agg_outtime_over");
                ValueCount total_count =  bucket.getAggregations().get("agg_total_count");
                Map<String,Object> busTop = new HashMap<>();
                busTop.put("shopperId", shopperId);
                busTop.put("outtime_quantity", outtime_over.getValue());
                busTop.put("total_quantity", total_count.getValue());
                objects.add(busTop);
            }
            return WebResult.ok(objects);
        }
    }


    /**
     * 根据超时率排行
     * @param topSize
     * @param request
     * @return
     * @throws IOException
     */
    @GetMapping(value = "/shopperTopByOvertimeRate")
    public WebResult<Object> getShopperTopListByOvertimeRate(@RequestParam(required = true, defaultValue = "15") Integer topSize, HttpServletRequest request) throws IOException {
        String agentId = request.getParameter("agentId");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        SearchRequest searchRequest = new SearchRequest();
        BoolQueryBuilder qbs = QueryBuilders.boolQuery();
        if(NumberUtils.isPositiveInteger(agentId)) {
            qbs.must(QueryBuilders.termsQuery("agentId", agentId));
        }
        qbs.must(QueryBuilders.termQuery("status", 8));
        qbs.must(QueryBuilders.termQuery("isPay", 1));
        BoolQueryBuilder deliverQbs = QueryBuilders.boolQuery();
        deliverQbs.should(QueryBuilders.termQuery("isDeliver", 0));
        deliverQbs.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("isDeliver")));
        qbs.must(deliverQbs);
        qbs.must(QueryBuilders.existsQuery("shopperId"));
        Date endDate = DatesUtil.getEndDayOfYesterDay();
        Date startDate = DatesUtil.getBeginDayOfYesterday();
        qbs.must(QueryBuilders.rangeQuery("createTime").from(startDate, true).to(endDate, true));
        TermsAggregationBuilder shopperIdBuilder = AggregationBuilders.terms("agg_shopperId").field("shopperId").size(topSize);
        SumAggregationBuilder agg_outtime_over = AggregationBuilders.sum("agg_outtime_over").script(new Script(ScriptType.STORED,null,"runfast_order_outtime_over_sum", new HashMap<>()));
        ValueCountAggregationBuilder agg_total_count = AggregationBuilders.count("agg_total_count").field("id");
//
//        Script script = new Script(ScriptType.INLINE, "painless", "return params.agg_outtime_over / params.agg_total_count;", new HashMap<>());
//        Map<String, String> bucketsPathsMap = new HashMap<>();
//        bucketsPathsMap.put("agg_outtime_over", "agg_outtime_over");
//        bucketsPathsMap.put("agg_total_count", "agg_total_count");
//        BucketScriptPipelineAggregationBuilder aggregatorBuilder = new BucketScriptPipelineAggregationBuilder("aggOvertimeRate", bucketsPathsMap, script);

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("OvertimeCount", 0);
        paramMap.put("totalCount", 0);
        ScriptedMetricAggregationBuilder scriptedMetricAggregationBuilder = AggregationBuilders.scriptedMetric("aggOvertimeRate")
                .initScript(new Script("params._agg.OvertimeCount = 0;params._agg.totalCount=0;"))
                .mapScript(new Script("params._agg.totalCount+=1;if(doc['status'].value == 8 && doc['readyTime'].value > doc['disTime'].value){params._agg.OvertimeCount+=1;}"))
                .reduceScript(new Script("double OvertimeCount = 0; double totalCount = 0;for(m in params._aggs){OvertimeCount+=m.OvertimeCount;totalCount+=m.totalCount;}return OvertimeCount / totalCount;"));
        sourceBuilder.aggregation(shopperIdBuilder.subAggregation(agg_outtime_over).subAggregation(agg_total_count).subAggregation(scriptedMetricAggregationBuilder)).query(qbs);
        sourceBuilder.from(0).size(0);
        searchRequest.indices(INDEX).source(sourceBuilder).types(TYPE);
        System.out.println(searchRequest.source());
        SearchResponse response = restHighLevelClient.search(searchRequest);
        if(response.status() == null || response.status() != RestStatus.OK){
            return WebResult.fail("查询失败");
        }else {
            List<Object> objects = new ArrayList<>();
            Aggregations aggregations = response.getAggregations();
            Terms terms = aggregations.get("agg_shopperId");
            for(Terms.Bucket bucket : terms.getBuckets()){
                String shopperId = bucket.getKeyAsString();
                Sum outtime_over =  bucket.getAggregations().get("agg_outtime_over");
                ValueCount total_count =  bucket.getAggregations().get("agg_total_count");
                Map<String,Object> busTop = new HashMap<>();
                busTop.put("outtime_quantity", outtime_over.getValue());
                busTop.put("total_quantity", total_count.getValue());
                busTop.put("shopperId", shopperId);
                objects.add(busTop);
            }
            return WebResult.ok(objects);
        }
    }


    /**
     * 城市经理数据
     * @param agents
     * @param pageable
     * @return
     * @throws IOException
     */
    @GetMapping(value = "/city_manager_data")
    public WebResult getDataByAgent(String agents, @PageableDefault Pageable pageable) throws IOException {
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder parentQueryBuilder = QueryBuilders.boolQuery();
        parentQueryBuilder.must(QueryBuilders.termQuery("status", 8));
        parentQueryBuilder.must(QueryBuilders.termQuery("isPay", 1));
        if(agents != null && agents.length() > 0){
            parentQueryBuilder.must(QueryBuilders.termsQuery("agentId", agents.split(",")));
        }
        TermsAggregationBuilder aggAgentBuilder = AggregationBuilders.terms("agg_agentId").field("agentId").size(1000);
        SumAggregationBuilder agg_price = AggregationBuilders.sum("agg_price").field("price");
        ValueCountAggregationBuilder agg_num = AggregationBuilders.count("agg_num").field("id");
        SumAggregationBuilder agg_agentBusget = AggregationBuilders.sum("agg_agentBusget").field("agentBusget");
        sourceBuilder.query(parentQueryBuilder).aggregation(aggAgentBuilder.subAggregation(agg_price).subAggregation(agg_num).subAggregation(agg_agentBusget));
        sourceBuilder.from(0).size(0);
        searchRequest.source(sourceBuilder).indices(INDEX).types(TYPE);
        SearchResponse response = this.restHighLevelClient.search(searchRequest);
        if(response.status() == RestStatus.OK){
            List<Object> arrays = new ArrayList<>();
            Aggregations aggregations = response.getAggregations();
            if(aggregations != null){
                Terms agentTerms = aggregations.get("agg_agentId");
                if(agentTerms != null && agentTerms.getBuckets() != null){
                    for(Terms.Bucket bucket : agentTerms.getBuckets()){
                        Object keyObject = bucket.getKey();
                        if(keyObject != null && NumberUtils.isPositiveInteger(keyObject.toString()) && bucket != null && bucket.getAggregations() != null) {
                            Aggregations items = bucket.getAggregations();
                            Sum sumPrice = items.get("agg_price");
                            ValueCount sumNum = items.get("agg_num");
                            Sum aggAgentBusget = items.get("agg_agentBusget");

                            Map<String,Object> itemMap = new HashMap<>();
                            if(sumPrice != null){
                                itemMap.put("totalMoney", sumPrice.getValue());
                            }else{
                                itemMap.put("totalMoney", 0.0);
                            }
                            if(sumNum != null){
                                itemMap.put("num", sumNum.getValue());
                            }else{
                                itemMap.put("num", 0);
                            }
                            if(aggAgentBusget != null){
                                itemMap.put("totalAgentBusget", aggAgentBusget.getValue());
                            }else{
                                itemMap.put("totalAgentBusget", 0);
                            }
                            itemMap.put("agentId", Integer.parseInt(keyObject.toString()));
                            arrays.add(itemMap);
                        }
                    }
                }
            }
            return WebResult.ok(arrays);
        }
        return WebResult.fail("查询失败");
    }


    /**
     * 代理商销量
     * @param request
     * @return
     * @throws IOException
     */
    @GetMapping(value = "/agentSalesVolume")
    public WebResult getAgentSalesVolume(HttpServletRequest request) throws IOException {
        String agentIdStr = request.getParameter("agentId");
        if(!NumberUtils.isPositiveInteger(agentIdStr)){
            return WebResult.fail("代理商ID错误");
        }
        String startTimeStr = request.getParameter("startTime");
        String endtimeStr = request.getParameter("endTime");
        Long startTime = null;
        Long endTime = null;
        if(startTimeStr != null || endtimeStr != null) {
            if (!NumberUtils.isPositiveInteger(startTimeStr) || !NumberUtils.isPositiveInteger(endtimeStr)) {
                return WebResult.fail("时间错误");
            }
            startTime = Long.valueOf(startTimeStr);
            endTime = Long.valueOf(endtimeStr);
        }else{
            startTime = DatesUtil.getBeginDayOfLastMonth().getTime();
            endTime = DatesUtil.getEndDayOfLastMonth().getTime();
        }
        Integer agentId = Integer.valueOf(agentIdStr);
        BoolQueryBuilder parentQueryBuilder = QueryBuilders.boolQuery();
        parentQueryBuilder.must(QueryBuilders.termQuery("status", 8));
        parentQueryBuilder.must(QueryBuilders.termQuery("agentId", agentId));
        parentQueryBuilder.must(QueryBuilders.rangeQuery("createTime").from(startTime, true).to(endTime, true));
        //聚合查询
        SumAggregationBuilder sumactualPay = AggregationBuilders.sum("agg_actualPay").script(new Script(ScriptType.STORED, null,"runfast_order_actual_patyamount", new HashMap<>()));
        ValueCountAggregationBuilder countBuilder = AggregationBuilders.count("aggCount_id").field("id");

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(parentQueryBuilder).from(0).size(0).aggregation(sumactualPay).aggregation(countBuilder);
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.source(sourceBuilder).indices(INDEX).types(TYPE);
        SearchResponse response = this.restHighLevelClient.search(searchRequest);
        if(response.status() == RestStatus.OK){
            Aggregations aggregations = response.getAggregations();
            if(aggregations != null){
                Map<String, Object> resultMap = new HashMap<>();
                Sum actualPaySum = aggregations.get("agg_actualPay");
                if(actualPaySum != null) {
                    resultMap.put("amount", BigDecimal.valueOf(actualPaySum.getValue()).setScale(2, BigDecimal.ROUND_HALF_UP));
                }else{
                    resultMap.put("amount", 0.0);
                }
                ValueCount count = aggregations.get("aggCount_id");
                if(count != null){
                    resultMap.put("quantity", count.getValue());
                }else{
                    resultMap.put("quantity", 0);
                }
                return WebResult.ok(resultMap);
            }
        }
        return WebResult.fail("查询失败");
    }


    private Map<String, Object> initDayItem(int count, BigDecimal totalPay){
        Map<String,Object> sticItem = new HashMap<>();
        sticItem.put("quantity", count);
        sticItem.put("amount", totalPay);
        return sticItem;
    }

    public class Statistical {

        private Map<Integer, BigDecimal> hoursAmount = new HashMap<>();

        private Map<Integer, Integer> hoursQun = new HashMap<>();

        private BigDecimal agentBusget = BigDecimal.ZERO;

        private BigDecimal amount = BigDecimal.ZERO;

        private Integer quantity = 0;

        private BigDecimal showps = BigDecimal.ZERO;

        private BigDecimal subsidy = BigDecimal.ZERO;

        private Map<Integer, BigDecimal> payTypeAmount = new HashMap<>();

        private Map<Integer, BigDecimal> payPlatform = new HashMap<>();

        private BigDecimal activityPrice = BigDecimal.ZERO;

        public void add(int hour, int quantity, BigDecimal activityprice, BigDecimal agentBusget, BigDecimal refund, BigDecimal totalPay, BigDecimal subsidy, BigDecimal showps, int payType, int loginOn, Integer isDeliver){
            BigDecimal actualTotalPay = null;
            if(refund == null || refund.compareTo(BigDecimal.ZERO) == 0) {
                actualTotalPay = totalPay;
            }else{
                actualTotalPay = totalPay.subtract(refund);
            }
            if(this.hoursAmount.containsKey(hour)){
                this.hoursAmount.put(hour, this.hoursAmount.get(hour).add(actualTotalPay));
            }else{
                this.hoursAmount.put(hour, actualTotalPay);
            }
            if(this.hoursQun.containsKey(hour)){
                this.hoursQun.put(hour, this.hoursQun.get(hour) + quantity);
            }else{
                this.hoursQun.put(hour, quantity);
            }
            this.agentBusget = this.agentBusget.add(agentBusget);
            this.amount = this.amount.add(actualTotalPay);
            this.quantity = this.quantity + quantity;
            if(isDeliver == null || isDeliver.equals(0)) {
                this.showps = this.showps.add(showps);
            }
            if(subsidy != null && subsidy.compareTo(BigDecimal.ZERO) > 0) {
                this.subsidy = this.subsidy.add(subsidy);
            }
            if(this.payTypeAmount.containsKey(payType)){
                this.payTypeAmount.put(payType, this.payTypeAmount.get(payType).add(actualTotalPay));
            }else{
                this.payTypeAmount.put(payType, actualTotalPay);
            }
            if(this.payPlatform.containsKey(loginOn)){
                this.payPlatform.put(loginOn, this.payPlatform.get(loginOn).add(actualTotalPay));
            }else{
                this.payPlatform.put(loginOn, actualTotalPay);
            }
            if(activityprice != null && activityprice.compareTo(BigDecimal.ZERO) > 0) {
                this.activityPrice = this.activityPrice.add(activityprice);
            }
        }

        public Map<Integer, BigDecimal> getHoursAmount() {
            return hoursAmount;
        }

        public Map<Integer, Integer> getHoursQun() {
            return hoursQun;
        }

        public BigDecimal getAgentBusget() {
            return agentBusget;
        }

        public BigDecimal getAmount() {
            return amount;
        }

        public Integer getQuantity() {
            return quantity;
        }

        public BigDecimal getShowps() {
            return showps;
        }

        public BigDecimal getSubsidy() {
            return subsidy;
        }

        public Map<Integer, BigDecimal> getPayTypeAmount() {
            return payTypeAmount;
        }

        public Map<Integer, BigDecimal> getPayPlatform() {
            return payPlatform;
        }

        public BigDecimal getActivityPrice() {
            return activityPrice;
        }
    }

    public class Contrast<T> {

        T _this;
        T _last;

        public T get_this() {
            return _this;
        }

        public T get_last() {
            return _last;
        }
    }


}
